package cn.endeavour.user.service.impl;

import cn.endeavour.basic.exception.BusinessException;
import cn.endeavour.basic.service.impl.BaseServiceImpl;
import cn.endeavour.basic.util.LoginContextUtil;
import cn.endeavour.basic.util.MD5Utils;
import cn.endeavour.basic.util.StrUtils;
import cn.endeavour.user.constant.UserConstant;
import cn.endeavour.user.domain.LoginInfo;
import cn.endeavour.user.domain.User;
import cn.endeavour.user.dto.UserDto;
import cn.endeavour.user.mapper.LoginInfoMapper;
import cn.endeavour.user.mapper.UserMapper;
import cn.endeavour.user.service.IUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 业务层实现
 */
@Service
public class UserServiceImpl extends BaseServiceImpl<User> implements IUserService {

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;

    @Autowired
    private LoginInfoMapper loginInfoMapper;

    @Autowired
    private UserMapper userMapper;

    @Override
    public void delete(Long id) {
        // 先查出对象
        User user = userMapper.loadById(id);
        // 删除中间表
        loginInfoMapper.remove(id);
        super.delete(id);
    }

    @Override
    @Transactional
    public void update(User user) {
        // 先查询出login的id
        User dbUser = userMapper.loadById(user.getId());
        // 转换对象
        LoginInfo loginInfo = user2LoginInfo(user);
        loginInfo.setId(dbUser.getId());
        // 对登录表进行修改
        loginInfoMapper.update(loginInfo);
        super.update(user);
    }

    @Override
    public void sendCode(Map<String, String> params) {
        // 获取phone和type
        String phone = params.get("phone");
        String type = params.get("type");
        // 先判断号码是否为空
        if (!StringUtils.hasLength(phone)) {
            throw new BusinessException("手机号码不能为空");
        }
        // 用户注册
        if ("register".equals(type)) {
            //  不能被注册
            User user = userMapper.findByPhone(phone);
            if (user != null) {
                throw new BusinessException("用户已经被注册！");
            }
            String key = UserConstant.REGISTER_CODE_PREFIX + phone;
            sendCode(key);
        } else if ("binder".equals(type)) { //绑定
            String key = UserConstant.BINDER_CODE_PREFIX + phone;
            sendCode(key);
        } else if("login".equals(type)) {
            String key = UserConstant.LOGIN_CODE_PREFIX + phone;
            sendCode(key);
        }
    }

    /**
     * 获取验证码
     * @param key 保存在Redis中的key值
     */
    private void sendCode(String key){
        // 然后在Redis中去查找验证码
        Object codeObj = redisTemplate.opsForValue().get(key);
        String code = null;
        // 如果验证码没有过期
        if (codeObj != null) {
            String codeStr = (String) codeObj;
            // 然后得到验证码生成时间
            String time = codeStr.split(":")[1];
            // 判断时间是否超过了重发时间
            if (System.currentTimeMillis() - Long.parseLong(time) < 60 * 1000) {
                throw new BusinessException("请不要多次发送验证码");
            } else {
                code = codeStr.split(":")[0];
            }
        } else {
            // 是第一次或者验证码已经过期
            // 生成验证码
            code = StrUtils.getRandomString(4);
        }
        // 保存在Redis中,然后设置过期时间为三分钟
        redisTemplate.opsForValue().set(key, code + ":" + System.currentTimeMillis(), 3, TimeUnit.MINUTES);
        // SmsUtil.sendSms(phone, "你的验证码为：" + code + "，请在3分钟之内使用!" );
        System.out.println("你的验证码为：" + code + "，请在3分钟之内使用!");
    }

    @Override
    @Transactional
    public void registerByPhone(UserDto userDto) {
        // 首先判断非空
        if (StringUtils.isEmpty(userDto.getPhone()) || StringUtils.isEmpty(userDto.getVerifyCode()) || StringUtils.isEmpty(userDto.getPassword()) || StringUtils.isEmpty(userDto.getRePassword())) {
            throw new BusinessException("请输入相关信息在注册");
        }
        // 判断两次密码是否相等
        if (!userDto.getPassword().equals(userDto.getRePassword())) {
            throw new BusinessException("两次输入的密码必须一致");
        }
        // 判断验证是否过期,获取验证码
        Object codeObj = redisTemplate.opsForValue().get(UserConstant.REGISTER_CODE_PREFIX + userDto.getPhone());
        if (codeObj == null) {
            throw new BusinessException("验证码无效,请重新获取验证码");
        }
        // 获取之前保存的验证码
        String verifyCodeStr = (String) codeObj;
        String verifyCode = verifyCodeStr.split(":")[0];
//        System.out.println(verifyCode);
//        System.err.println(userDto);
        // 判断验证码是否相同
        if (!verifyCode.equalsIgnoreCase(userDto.getVerifyCode())) {
            throw new BusinessException("验证码错误,重新输入验证码");
        }
        // 判断手机号码是否注册
        User userTmp = userMapper.findByPhone(userDto.getPhone());
        if (userTmp != null) {
            throw new BusinessException("该手机号码已经注册,请直接登录");
        }
        // 转换对象
        User user = userDto2User(userDto);
        LoginInfo info = user2LoginInfo(user);
        // 保存登录信息表
        loginInfoMapper.save(info);
        user.setLoginInfo_id(info.getId());
        // 保存用户表
        userMapper.save(user);
    }

    @Override
    public void logout(HttpServletRequest request) {
        String token = request.getHeader("token");
        // 移除token
        if (token != null) {
            redisTemplate.delete(token);
        }

    }

    @Override
    public void unEnable(Long id) {
        // 查询id
        User user = userMapper.loadById(id);
        // 设置状态
        user.setState(1);
        userMapper.update(user);

    }

    @Override
    public void enable(Long id) {
        // 查询id
        User user = userMapper.loadById(id);
        // 设置状态
        user.setState(0);
        userMapper.update(user);
    }

    /**
     * 将user对象转换为LoginInfo对象
     * @param user 用户
     * @return LoginInfo对象
     */
    private LoginInfo user2LoginInfo(User user) {
        LoginInfo loginInfo = new LoginInfo();
        // 复制数据
        BeanUtils.copyProperties(user, loginInfo);
        return loginInfo;
    }

    /**
     * 将用户dto转换用户
     * @param userDto
     * @return
     */
    private User userDto2User(UserDto userDto) {
        User user = new User();
        // 进行赋值
        user.setUsername(userDto.getPhone());
        user.setPhone(userDto.getPhone());
        // 对密码加盐
        String salt = StrUtils.getComplexRandomString(32);
        // 对密码进行加密
        String md5Pwd = MD5Utils.encrypByMd5(userDto.getPassword() + salt);
        user.setSalt(salt);
        user.setPassword(md5Pwd);
        return user;
    }
}

